# from django.contrib.auth.mixins import LoginRequiredMixin
import json
import time
from decimal import Decimal

from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction
from django.shortcuts import render

# Create your views here.
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from apps.areas.models import Address
from apps.goods.models import Goods
from apps.orders.models import OrderInfo, OrderGoods
from utils.response_code import RETCODE
from utils.views import LoginRequiredJSONMixinView


class OrderView(LoginRequiredMixin, View):
    """展示用户订单"""

    def get(self, request):
        """提供订单结算页面"""
        # 获取用户
        user = request.user
        # 数据库查询出当前用户的收货地址
        try:
            address = Address.objects.filter(user=request.user, is_deleted=False)
        except Address.DoesNotExist:
            return http.HttpResponseBadRequest('address is not ')
        # 接下来查询redis数据库中的所勾选的商品信息
        # 连接redis数据库
        redis_conn = get_redis_connection('carts')
        # 查询购物车 和 勾选状态
        redis_cart = redis_conn.hgetall('carts_%s' % user.id)
        redis_selected = redis_conn.smembers('selected_%s' % user.id)
        # 定义一个字典 用于存放值
        cart = {}
        for sku_id in redis_selected:
            cart[int(sku_id)] = int(redis_cart[sku_id])

        # 准备初始值
        total_count = 0  # 数量
        total_amount = Decimal(0.00)
        # 查询商品信息
        skus = Goods.objects.filter(id__in=cart.keys())
        for sku in skus:
            sku.count = cart[sku.id]  # 数量
            # print("数量",sku.count, type(sku.count))
            # print("价格",sku.current_price, type(sku.current_price))
            sku.amount = sku.count * Decimal(sku.current_price)  # 总价
            total_count += sku.count
            total_amount += Decimal(sku.amount)
        # 运费
        freight = Decimal('10.00')
        # 创建响应对象
        context = {
            'addresses': address,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight
        }

        return render(request, 'place_order.html', context)


class OrderCommit(LoginRequiredJSONMixinView, View):
    """添加订单"""

    def post(self, request):
        """订单信息和订单商品信息"""
        # 获取请求体中的参数
        json_dict = json.loads(request.body.decode())
        # 获取收货地址id 和 支付方式id
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        # 校验参数
        if not all([address_id, pay_method]):
            return http.HttpResponseBadRequest('缺少必要参数')
        # 从数据库查询 看收货地址是否 添加
        try:
            address = Address.objects.get(id=address_id)
        except Address.DoesNotExist:
            return http.HttpResponseBadRequest('addresses is not ')
        # 判断支付方法是否合法
        if int(pay_method) not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseBadRequest('支付方法有误')

        # 获取登录用户
        user = request.user
        # 生成订单编号：年月日时分秒+用户编号
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
        # ----------修改了代码--------------
        # 在保存订单信息之前 开启事务
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
            try:
                # 保存（创建）订单基本信息
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM[
                        'ALIPAY'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']
                )

                # 连接redis数据库
                redis_conn = get_redis_connection('carts')
                # 获取购物车信息 和 商品勾选信息
                redis_cart = redis_conn.hgetall('carts_%s' % user.id)
                redis_selected = redis_conn.smembers('selected_%s' % user.id)
                # 定义一个字典 存放勾选的商品
                carts = {}
                for sku_id in redis_selected:
                    carts[int(sku_id)] = int(redis_cart[sku_id])  # {3:1,5:1}

                # 循环cart所有key 就是所有的商品id
                for sku_id in carts.keys():
                    # ----修改了代码----
                    for sql_loop in range(3):
                        # 数据库查询 这个商品是否存在
                        sku = Goods.objects.get(id=sku_id)
                        print("{}--正在下单id={}".format(request.user.username, sku_id))
                        # ——----修改了代码-------
                        # 读取原始库存
                        origin_stock = sku.slave  # 库存
                        origin_sales = sku.sales  # 销量

                        # 获取数量
                        sku_count = carts[sku.id]
                        # 判断数量是否超过库存
                        if sku_count > sku.slave:
                            # 如果用户购买的商品超过了库存 就回滚
                            transaction.savepoint_rollback(save_id)
                            return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})

                        # 乐观锁更新库存和销量
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count
                        # 数据库查询 商品的库存是否还等于下单时查询的库存数量 并更新数据库
                        result = Goods.objects.filter(id=sku_id, slave=origin_stock).update(
                            slave=new_stock, sales=new_sales
                        )
                        print(result)
                        # 如果result修改的数量为0 说明数据库没有查询到 没有修改 下单失败
                        if result == 0:
                            if sql_loop == 2:
                                # 事务回滚
                                transaction.savepoint_rollback(save_id)
                                return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '下单失败2'})
                            else:
                                continue
                        else:
                            break

                    # 保存订单商品信息
                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        count=sku_count,
                        price=sku.current_price
                    )

                    # 修改订单中的总价和数量
                    order.total_count += sku_count
                    print("数量", sku_count, type(sku_count))
                    print("数量", sku.current_price, type(sku.current_price))
                    order.total_amount += (sku_count * Decimal(sku.current_price))
                    # 测试用的，可以删除（注意下方的7是当前我在测试时一个用户的id小于7而另外一个是7，所以才写的7，根据实际编写即可）
                    if request.user.id < 100:
                        for i in range(10):
                            print("用户{}正在延时{}提交中...".format(request.user.username, i + 1))
                            time.sleep(1)
                # 最后总价 邮费加上总价
                order.freight += order.total_amount
                # 保存订单信息
                order.save()
            except Exception as e:  # -----修改了代码------
                # 如果 数据库操作出现了错误 就回滚
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败555'})
            # ------修改了代码------
            # 提交订单成功 提交事务
            transaction.savepoint_commit(save_id)
        # 清除redis购物车中的已经结算的商品
        # 创建管道
        pl = redis_conn.pipeline()
        pl.hdel('carts_%s' % user.id, *redis_selected)
        pl.srem('selected_%s' % user.id, *redis_selected)
        # 执行管道
        pl.execute()

        # 返回响应结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})

class OrderSuccess(LoginRequiredMixin, View):
    """展示用户订单"""

    def get(self, request):
        # 获取查询字符串
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')
        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method': pay_method
        }

        return render(request, 'order_success.html', context)